package com.hydra.framework.router;

import android.util.Log;
import androidx.annotation.MainThread;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.hydra.framework.router.interceptor.IRouterInterceptor;
import com.hydra.framework.router.interceptor.RouterInterceptor;
import com.hydra.framework.router.interceptor.RouterInterceptorList;
import com.hydra.framework.router.receiver.RouterReceiver;
import com.hydra.framework.router.receiver.RouterReceiverList;
import com.hydra.framework.util.CollectionUtil;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map.Entry;

import static com.hydra.framework.router.JRouter.JROUTER_LOG_TAG;

/**
 * Created by Hydra on 2017/8/3.
 *
 */
class JRouterDispatcher {

    private HashMap<String, RouterReceiverList> mReceivers = new HashMap<>();

    private HashMap<String, RouterInterceptorList> mInterceptors = new HashMap<>();

    private final Object mReceiversLock = new byte[0];

    private final Object mInterceptorsLock = new byte[0];

    @MainThread
    public void notifyEvent(RouterIntent routerIntent) {
        RouterInterceptorList interceptorList;

        synchronized (mInterceptorsLock) {
            interceptorList = mInterceptors.get(routerIntent.url);
        }

        boolean intercepted = false;

        if(interceptorList != null) {
            intercepted = interceptorList.invokeToInterceptors(routerIntent);
        }

        if(!intercepted) {
            RouterReceiverList receiverList;

            synchronized (mReceiversLock) {
                receiverList = mReceivers.get(routerIntent.url);
            }

            if(receiverList != null) {
                receiverList.invokeToReceivers(routerIntent);
            } else {
                Log.e(JROUTER_LOG_TAG, "no receiver receive the url : " + routerIntent.url);
            }
        }
    }

    public void addRouter(@NonNull Class<?> receiverClass, int flags, int priority, @NonNull String... paths) {
        if(CollectionUtil.isEmpty(paths)) {
            Log.e(JROUTER_LOG_TAG, "an router receiver must connect with at least one url !");
            return;
        }

        for(String path : paths) {
            addRouter(path, new RouterReceiver(path, priority, receiverClass, flags));
        }
    }

    public void addRouter(String url, RouterReceiver routerReceiver) {
        RouterReceiverList receiverList;

        synchronized (mReceiversLock) {
            receiverList = mReceivers.get(url);

            if (receiverList == null) {
                receiverList = new RouterReceiverList();
                mReceivers.put(url, receiverList);
            }
        }

        receiverList.add(routerReceiver);
    }

    public void addInterceptor(@NonNull IRouterInterceptor interceptor, int priority, @NonNull String... paths) {
        if(CollectionUtil.isEmpty(paths)) {
            Log.e(JROUTER_LOG_TAG, "an router interceptor must connect with at least one url !");
            return;
        }

        for(String path : paths) {
            addInterceptor(path, new RouterInterceptor(path, interceptor, priority));
        }
    }

    public void addInterceptor(String url, RouterInterceptor routerInterceptor) {
        RouterInterceptorList interceptorList;

        synchronized (mInterceptorsLock) {
            interceptorList = mInterceptors.get(url);

            if (interceptorList == null) {
                interceptorList = new RouterInterceptorList();
                mInterceptors.put(url, interceptorList);
            }
        }

        interceptorList.add(routerInterceptor);
    }

    /**
     * 因为一个interceptor或者receiver可以接收多个URL，支持只remove部分url
     *
     * 如果传的URL是空，则移除此Interceptor接收的所有URL
     */
    public void removeInterceptor(@NonNull IRouterInterceptor interceptor, @Nullable String... paths) {
        if (!CollectionUtil.isEmpty(paths)) {
            for (String path : paths) {
                RouterInterceptorList interceptorList = mInterceptors.get(path);

                if (interceptorList != null) {
                    interceptorList.remove(interceptor);
                }
            }
        } else {
            synchronized (mInterceptorsLock) {
                Iterator<Entry<String, RouterInterceptorList>> ite = mInterceptors.entrySet().iterator();

                while (ite.hasNext()) {
                    ite.next().getValue().remove(interceptor);
                }
            }
        }
    }

    /**
     * TODO
     * 这里本来可以再搞个map以class当key，然后以一个class的所有url当value，
     * 但是感觉没啥必要，后面有需要可以加上，先遍历一遍吧，耗时差不多
     */
    public void removeRouter(@NonNull Class<?> receiverClass, @Nullable String... paths) {
        if (!CollectionUtil.isEmpty(paths)) {
            for (String path : paths) {
                RouterReceiverList receiverList = mReceivers.get(path);

                if (receiverList != null) {
                    receiverList.remove(receiverClass);
                }
            }
        } else {
            synchronized (mReceiversLock) {
                Iterator<Entry<String, RouterReceiverList>> ite = mReceivers.entrySet().iterator();

                while (ite.hasNext()) {
                    ite.next().getValue().remove(receiverClass);
                }
            }
        }
    }

    public void removeRoutersOfUrl(@NonNull String url) {
        synchronized (mReceiversLock) {
            mReceivers.remove(url);
        }
    }

    public void removeInterceptorsOfUrl(@NonNull String url) {
        synchronized (mInterceptorsLock) {
            mInterceptors.remove(url);
        }
    }
}
